﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System.Collections.Generic;
using System.Windows.Media.Animation;

namespace Xceed.Silverlight.ListBox
{
  internal class ViewChangingTransitionAnimation : TransitionAnimation
  {
    internal ViewChangingTransitionAnimation( ListBoxAnimationSettings animationSettings )
      : base( animationSettings.GetViewChangingDuration() )
    {

      m_addededItemsOpacityEasing = new PowerEase()
      {
        Power = 2,
        EasingMode = EasingMode.EaseIn
      };

      m_removedItemsOpacityEasing = new PowerEase()
      {
        Power = 2,
        EasingMode = EasingMode.EaseOut
      };

      m_changedItemsMovementEasing = new PowerEase()
      {
        Power = 2,
        EasingMode = EasingMode.EaseIn
      };

    }

    internal override void AddContainer( ListBoxContainer container )
    {
      if( !this.IsRunning )
        return;

      LayoutChangeInfo layoutChange = this.CreateLayoutChangeInfo();

      if( this.PrepareContainer( container, layoutChange ) )
      {
        //Update the element with start time, ensure that as soon as "start" completes, state if correct for all items.
        if( !this.UpdateContainer( 0d, container ) )
        {
          //If both preparation let pass the item and update did not filter it out, mark the item as managed by TransitionAnimation
          this.HandledItems.Add( container );
        }
      }

    }

    internal override void DetermineLayoutChangesCore( Dictionary<ListBoxContainer, LayoutChangeInfo> changedElements )
    {
      //Nothing additional to do
    }

    internal override bool PrepareContainerCore( ListBoxContainer container, LayoutChangeInfo changeInfo )
    {
      if( changeInfo == null )
        throw new ListBoxInternalException();

      if( changeInfo.ChangeType == ChangeType.ElementAdded )
      {
        OpacityAnimation opacityAnimation = new OpacityAnimation();
        ( ( IAnimation )opacityAnimation ).AnimationDirection = AnimationDirection.ToReferencePosition;
        ( ( IAnimation )opacityAnimation ).EasingFunction = m_addededItemsOpacityEasing;
        ( ( IAnimation )opacityAnimation ).ParentTransition = this;
        opacityAnimation.OpacityChange = -changeInfo.OpacityChange;
        container.AddAnimation( opacityAnimation );

        return true;
      }
      else if( changeInfo.ChangeType == ChangeType.ElementRemoved )
      {
        OpacityAnimation opacityAnimation = new OpacityAnimation();
        ( ( IAnimation )opacityAnimation ).AnimationDirection = AnimationDirection.FromReferencePosition;
        ( ( IAnimation )opacityAnimation ).EasingFunction = m_removedItemsOpacityEasing;
        ( ( IAnimation )opacityAnimation ).ParentTransition = this;
        opacityAnimation.OpacityChange = changeInfo.OpacityChange;
        container.AddAnimation( opacityAnimation );
        return true;
      }
      else
      {
        ScaleAnimation scaleAnimation = new ScaleAnimation();
        ( ( IAnimation )scaleAnimation ).EasingFunction = m_changedItemsMovementEasing;
        ( ( IAnimation )scaleAnimation ).ParentTransition = this;
        scaleAnimation.ScaleChange = changeInfo.ScaleChange;
        container.AddAnimation( scaleAnimation );

        RotateAnimation rotateAnimation = new RotateAnimation();
        ( ( IAnimation )rotateAnimation ).EasingFunction = m_changedItemsMovementEasing;
        ( ( IAnimation )rotateAnimation ).ParentTransition = this;
        rotateAnimation.AngleChange = changeInfo.AngleChange;
        container.AddAnimation( rotateAnimation );

        SizeAnimation sizeAnimation = new SizeAnimation();
        ( ( IAnimation )sizeAnimation ).EasingFunction = m_changedItemsMovementEasing;
        ( ( IAnimation )sizeAnimation ).ParentTransition = this;
        sizeAnimation.WidthChange = changeInfo.WidthChange;
        sizeAnimation.HeightChange = changeInfo.HeightChange;
        sizeAnimation.MaximumWidthChange = changeInfo.MaximumWidthChange;
        sizeAnimation.MaximumHeightChange = changeInfo.MaximumHeightChange;
        container.AddAnimation( sizeAnimation );

        PositionAnimation positionAnimation = new PositionAnimation();
        ( ( IAnimation )positionAnimation ).EasingFunction = m_changedItemsMovementEasing;
        ( ( IAnimation )positionAnimation ).ParentTransition = this;
        positionAnimation.XChange = changeInfo.XChange;
        positionAnimation.YChange = changeInfo.YChange;
        container.AddAnimation( positionAnimation );

        OpacityAnimation opacityAnimation = new OpacityAnimation();
        ( ( IAnimation )opacityAnimation ).EasingFunction = m_addededItemsOpacityEasing;
        ( ( IAnimation )opacityAnimation ).ParentTransition = this;
        opacityAnimation.OpacityChange = 0.0d;
        container.AddAnimation( opacityAnimation );

        return true;
      }
    }

    internal override bool UpdateContainerCore( double normalizedElapsedTime, ListBoxContainer container )
    {
      if( container == null )
        throw new ListBoxInternalException();

      container.UpdateAnimations( normalizedElapsedTime );

      //There is no custom animations in this transition, only those handled by the EasingFunctions.
      //Since I have no custom timeline, I do not have to decide when its "finished". Returning false
      //will just make it so that the animation will proceed for every frame of every item.
      return false;
    }

    internal override void CleanContainerCore( ListBoxContainer container )
    {

      if( container == null )
        throw new ListBoxInternalException();
    }

    internal override LayoutChangeInfo CreateLayoutChangeInfo()
    {
      return new LayoutChangeInfo();
    }

    private IEasingFunction m_removedItemsOpacityEasing;
    private IEasingFunction m_changedItemsMovementEasing;
    private IEasingFunction m_addededItemsOpacityEasing;
  }
}
